﻿using ProtoBuf;
using System;
using System.IO;

/// <summary>
/// 服务端和客户端的公有类
/// </summary>
public static class Common
{
    #region 字节解析

    /// <summary>
    /// 合并协议（加密）
    /// </summary>
    /// <typeparam name="T">协议内容类型</typeparam>
    /// <param name="type">协议号</param>
    /// <param name="t">协议内容</param>
    /// <returns>合并后的数据</returns>
    public static byte[] ComposeData<T>(MsgType type, T t)
    {
        //合并类型和内容
        byte[] arrType = type.Serialize();
        byte[] arrData = t.Serialize();
        byte[] arrSend = MergerArray(arrType, arrData);
        if (arrType.Length != 3)
            throw new Exception("协议号的字节长度错误=" + arrType.Length);
        //加密
        arrSend = arrSend.AesByte();
        return arrSend;
    }

    /// <summary>
    /// 解析协议（解密）
    /// </summary>
    /// <param name="arrReci">协议内容</param>
    /// <returns>协议号</returns>
    public static MsgType ParseMessageType(this byte[] arrReci, out byte[] arrData)
    {
        //解密
        arrReci = arrReci.UnAesByte();
        //解析类型
        byte[] arrType = new byte[3];
        Array.Copy(arrReci, arrType, 3);
        //解析内容
        arrData = new byte[arrReci.Length - 3];
        Array.Copy(arrReci, 3, arrData, 0, arrData.Length);

        MsgType type = arrType.DeSerialize<MsgType>();
        return type;
    }
    #endregion

    #region Protobuf

    /// <summary>
    /// Protobuf序列化
    /// </summary>
    /// <typeparam name="T">要序列化的实体的类型</typeparam>
    /// <param name="t">要序列化的实体</param>
    /// <returns>序列化后的字节数组</returns>
    public static byte[] Serialize<T>(this T t)
    {
        using (MemoryStream ms = new MemoryStream())
        {
            Serializer.Serialize<T>(ms, t);
            return ms.ToArray();
        }
    }

    /// <summary>
    /// ProtoBuf反序列化
    /// </summary>
    /// <typeparam name="T">反序列化后的实体的类型</typeparam>
    /// <param name="bytes">要反序列化的字节数组</param>
    /// <returns>反序列化后的实体</returns>
    public static T DeSerialize<T>(this byte[] bytes)
    {
        using (MemoryStream ms = new MemoryStream(bytes))
        {
            T t = Serializer.Deserialize<T>(ms);
            return t;
        }
    }

    #endregion

    #region 保存读取本地文件

    /// <summary>
    /// 保存数据到文件
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    /// <param name="t">数据实体</param>
    /// <param name="path">文件路径</param>
    public static void SaveFile<T>(T t, string path)
    {
        if (path == string.Empty)
            throw new Exception("保存数据文件路径为空！");

        FileStream fs = new FileStream(path, FileMode.Create);
        byte[] data = t.Serialize();
        fs.Write(data, 0, data.Length);
        fs.Close();
    }

    /// <summary>
    /// 从文件读取数据
    /// </summary>
    /// <typeparam name="T">数据类型</typeparam>
    /// <param name="path">文件路径</param>
    /// <returns>数据实体</returns>
    public static T LoadFile<T>(string path) where T : class, new()
    {
        if (path == string.Empty)
            throw new Exception("读取数据文件路径为空！");

        if (!File.Exists(path))
            return null;// new T();

        FileStream fs = new FileStream(path, FileMode.Open);
        byte[] data = new byte[fs.Length];
        fs.Read(data, 0, data.Length);
        fs.Close();
        T t = data.DeSerialize<T>();
        return t;
    }

    #endregion

    #region 其他

    /// <summary>
    /// 格式化字符串（方括号）
    /// </summary>
    /// <param name="str">初始字符串</param>
    /// <returns>格式化后字符串</returns>
    public static string Format(this string str)
    {
        return "[" + str + "]";
    }

    /// <summary>
    /// 格式化Socket
    /// </summary>
    /// <param name="isSend">是否是发送</param>
    /// <param name="type">协议类型</param>
    /// <param name="arr">协议数组</param>
    /// <param name="str">协议内容</param>
    /// <returns>格式化Socket的字符串</returns>
    public static string FormatSocket(bool isSend, MsgType type, byte[] arr, string str = null)
    {
        return (isSend ? "发" : "收") + (type.ToString() + "_" + arr.Length.ToString()).Format() + (str == null ? "" : "=" + str);
    }

    /// <summary>
    /// 合并数组
    /// </summary>
    /// <param name="arr1">第一个数组</param>
    /// <param name="arr2">第二个数组</param>
    /// <returns>合并后的数组</returns>
    public static byte[] MergerArray(byte[] arr1, byte[] arr2)
    {
        byte[] result = new byte[arr1.Length + arr2.Length];
        arr1.CopyTo(result, 0);
        arr2.CopyTo(result, arr1.Length);
        return result;
    }

    #endregion
}
